package com.example.erat.service.impl;

import com.example.erat.dto.CourseDTO;
import com.example.erat.dto.ExperimentDTO;
import com.example.erat.entity.Course;
import com.example.erat.entity.Experiment;
import com.example.erat.exception.BusinessException;
import com.example.erat.repository.CourseRepository;
import com.example.erat.repository.ExperimentRepository;
import com.example.erat.service.CourseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 课程服务实现
 */
@Slf4j
@Service
public class CourseServiceImpl implements CourseService {

    @Autowired
    private CourseRepository courseRepository;
    
    @Autowired
    private ExperimentRepository experimentRepository;

    @Override
    @Transactional
    public CourseDTO createCourse(CourseDTO courseDTO) {
        // 检查课程编号是否已存在
        if (courseRepository.existsByCourseCode(courseDTO.getCourseCode())) {
            throw new BusinessException("课程编号已存在");
        }
        
        // 检查课程名称是否已存在
        if (courseRepository.existsByName(courseDTO.getName())) {
            throw new BusinessException("课程名称已存在");
        }
        
        Course course = new Course();
        BeanUtils.copyProperties(courseDTO, course);
        
        Course savedCourse = courseRepository.save(course);
        
        CourseDTO result = new CourseDTO();
        BeanUtils.copyProperties(savedCourse, result);
        result.setExperimentCount(0);
        
        log.info("创建课程成功: {}", result.getName());
        return result;
    }

    @Override
    @Transactional
    public CourseDTO updateCourse(CourseDTO courseDTO) {
        // 检查课程是否存在
        Course course = courseRepository.findById(courseDTO.getId())
                .orElseThrow(() -> new BusinessException("课程不存在"));
        
        // 检查课程编号是否已存在（如果修改了编号）
        if (!course.getCourseCode().equals(courseDTO.getCourseCode()) && 
            courseRepository.existsByCourseCode(courseDTO.getCourseCode())) {
            throw new BusinessException("课程编号已存在");
        }
        
        // 检查课程名称是否已存在（如果修改了名称）
        if (!course.getName().equals(courseDTO.getName()) && 
            courseRepository.existsByName(courseDTO.getName())) {
            throw new BusinessException("课程名称已存在");
        }
        
        // 更新课程信息
        course.setCourseCode(courseDTO.getCourseCode());
        course.setName(courseDTO.getName());
        course.setDescription(courseDTO.getDescription());
        course.setSemester(courseDTO.getSemester());
        
        Course updatedCourse = courseRepository.save(course);
        
        CourseDTO result = new CourseDTO();
        BeanUtils.copyProperties(updatedCourse, result);
        result.setExperimentCount(updatedCourse.getExperiments().size());
        
        log.info("更新课程成功: {}", result.getName());
        return result;
    }

    @Override
    @Transactional
    public void deleteCourse(Long id) {
        // 检查课程是否存在
        Course course = courseRepository.findById(id)
                .orElseThrow(() -> new BusinessException("课程不存在"));
        
        // 删除课程（级联删除实验）
        courseRepository.delete(course);
        
        log.info("删除课程成功: {}", course.getName());
    }

    @Override
    public CourseDTO getCourseById(Long id) {
        // 检查课程是否存在
        Course course = courseRepository.findById(id)
                .orElseThrow(() -> new BusinessException("课程不存在"));
        
        CourseDTO result = new CourseDTO();
        BeanUtils.copyProperties(course, result);
        result.setExperimentCount(course.getExperiments().size());
        
        // 转换实验列表
        List<ExperimentDTO> experiments = course.getExperiments().stream()
                .map(this::convertToExperimentDTO)
                .collect(Collectors.toList());
        result.setExperiments(experiments);
        
        return result;
    }

    @Override
    public List<CourseDTO> listCourses() {
        List<Course> courses = courseRepository.findAll();
        
        return courses.stream()
                .map(course -> {
                    CourseDTO dto = new CourseDTO();
                    BeanUtils.copyProperties(course, dto);
                    dto.setExperimentCount(course.getExperiments().size());
                    return dto;
                })
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public ExperimentDTO addExperiment(Long courseId, ExperimentDTO experimentDTO) {
        // 检查课程是否存在
        Course course = courseRepository.findById(courseId)
                .orElseThrow(() -> new BusinessException("课程不存在"));
        
        // 检查实验编号是否已存在
        if (experimentRepository.existsByExperimentCode(experimentDTO.getExperimentCode())) {
            throw new BusinessException("实验编号已存在");
        }
        
        // 检查实验名称在该课程中是否已存在
        if (experimentRepository.findByNameAndCourseId(experimentDTO.getName(), courseId) != null) {
            throw new BusinessException("该课程下已存在同名实验");
        }
        
        Experiment experiment = new Experiment();
        BeanUtils.copyProperties(experimentDTO, experiment);
        experiment.setCourse(course);
        
        Experiment savedExperiment = experimentRepository.save(experiment);
        
        log.info("添加实验成功: {}", savedExperiment.getName());
        return convertToExperimentDTO(savedExperiment);
    }

    @Override
    @Transactional
    public ExperimentDTO updateExperiment(ExperimentDTO experimentDTO) {
        // 检查实验是否存在
        Experiment experiment = experimentRepository.findById(experimentDTO.getId())
                .orElseThrow(() -> new BusinessException("实验不存在"));
        
        // 检查实验编号是否已存在（如果修改了编号）
        if (!experiment.getExperimentCode().equals(experimentDTO.getExperimentCode()) && 
            experimentRepository.existsByExperimentCode(experimentDTO.getExperimentCode())) {
            throw new BusinessException("实验编号已存在");
        }
        
        // 检查实验名称在该课程中是否已存在（如果修改了名称）
        if (!experiment.getName().equals(experimentDTO.getName()) && 
            experimentRepository.findByNameAndCourseId(experimentDTO.getName(), experiment.getCourse().getId()) != null) {
            throw new BusinessException("该课程下已存在同名实验");
        }
        
        // 更新实验信息
        experiment.setExperimentCode(experimentDTO.getExperimentCode());
        experiment.setName(experimentDTO.getName());
        experiment.setDescription(experimentDTO.getDescription());
        experiment.setDeadline(experimentDTO.getDeadline());
        
        Experiment updatedExperiment = experimentRepository.save(experiment);
        
        log.info("更新实验成功: {}", updatedExperiment.getName());
        return convertToExperimentDTO(updatedExperiment);
    }

    @Override
    @Transactional
    public void deleteExperiment(Long experimentId) {
        // 检查实验是否存在
        Experiment experiment = experimentRepository.findById(experimentId)
                .orElseThrow(() -> new BusinessException("实验不存在"));
        
        // 删除实验（级联删除提交记录）
        experimentRepository.delete(experiment);
        
        log.info("删除实验成功: {}", experiment.getName());
    }

    @Override
    public List<ExperimentDTO> listCourseExperiments(Long courseId) {
        // 检查课程是否存在
        if (!courseRepository.existsById(courseId)) {
            throw new BusinessException("课程不存在");
        }
        
        List<Experiment> experiments = experimentRepository.findByCourseId(courseId);
        
        return experiments.stream()
                .map(this::convertToExperimentDTO)
                .collect(Collectors.toList());
    }
    
    /**
     * 将Experiment实体转换为ExperimentDTO
     */
    private ExperimentDTO convertToExperimentDTO(Experiment experiment) {
        ExperimentDTO dto = new ExperimentDTO();
        BeanUtils.copyProperties(experiment, dto);
        
        // 设置课程相关信息
        if (experiment.getCourse() != null) {
            dto.setCourseId(experiment.getCourse().getId());
            dto.setCourseName(experiment.getCourse().getName());
        }
        
        return dto;
    }
} 